package com.clusterswisdom.horn.control;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.clusterswisdom.horn.api.db.DbUtil;
import com.clusterswisdom.horn.api.event.BaseProcessor;
import com.clusterswisdom.horn.api.exception.HornApiException;
import com.clusterswisdom.horn.api.ioc.HornResponse;
import com.clusterswisdom.horn.api.ioc.api.ApiConfig;
import com.clusterswisdom.horn.api.ioc.api.HornConfig;
import com.clusterswisdom.horn.api.ioc.api.ResponseType;

public class NormalRequestProcess extends BaseProcessor {
	
	public static final String REQUEST_PARAM = "requestData";
	
	public static final String REQUEST_BIZDATA = "bizData";
	
	private String contentPath;
	
	private HttpServletRequest request;
	
	private HttpServletResponse response;
	
	private Long logId;
	
	private ApiConfig apiConfig;
	
	public NormalRequestProcess(String contentPath, HttpServletRequest request, HttpServletResponse response) {
		this.contentPath = contentPath;
		this.request = request;
		this.response = response;
	}

	public void run() {
		String[] requestParam = splitRequest(request);
		if (requestParam == null || requestParam.length != 3) {
			sendStatus(HornResponse.CODE_ERROR_PARAM, "request uri formate error.");
			return;
		}
		
		String requestData = request.getParameter(REQUEST_PARAM);
		if (requestData == null) {
			sendStatus(HornResponse.CODE_ERROR_PARAM, "can not get request data");
			return;
		}
		
		try {
			processRequest(requestParam, formateParam(requestData));
			
		} finally {
			DbUtil.getUtil().close();
			
		}
	}
	
	private void processRequest(String[] requestParam, JSONObject requestData) {
		apiConfig = HornConfig.getConfig().getApiConfig(requestParam[0], requestParam[1], requestParam[2]);
		if (apiConfig.isLog()) {
			logId = saveRequestToDb(requestParam[0], requestData);
		}
		
		try {
			HornResponse response = super.process(apiConfig, requestData);
			ResponseType type = apiConfig.getResponse().getType();
			if (ResponseType.STATUS.equals(type)) {
				sendStatus(response.getCode(), response.getMessage());
				 
			} else if (ResponseType.DATA.equals(type)) {
				sendData(apiConfig, response);
				 
			} else if (ResponseType.PUSH.equals(type)) {
				String pushResponse = super.pushData(apiConfig, response);
				sendResponse(JSON.parse(pushResponse));
				
			}
			
			DbUtil.getUtil().commit();
			
		} catch (HornApiException e) {
			e.printStackTrace();
			DbUtil.getUtil().rollback();
			sendStatus(HornResponse.CODE_ERROR_API, e.getMessage());
			
		} catch (Exception e) {
			e.printStackTrace();
			DbUtil.getUtil().rollback();
			sendStatus(HornResponse.CODE_ERROR_INVOKE, e.getMessage());
			
		}
	}
	
	private String sendData(ApiConfig config, HornResponse response) throws Exception {
		return sendResponse(response);
	}
	
	private String sendResponse(Object responseData) {
		String jsonString = JSON.toJSONString(responseData, SerializerFeature.QuoteFieldNames, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.UseISO8601DateFormat);
		if (logId != null) {
			DbUtil.getUtil().logResult(logId, getType(), jsonString);
		}
		
		response.setContentType("application/json;charset=UTF-8");
		try {
			response.getWriter().write(jsonString);
			response.getWriter().flush();
			return jsonString;
					
		} catch (IOException e) {
			e.printStackTrace();
			return e.getMessage();
			
		} 
	}
	
	private String getType() {
		if (apiConfig == null || apiConfig.getResponse() == null) {
			return "exception";
			
		}
		
		return apiConfig.getResponse().getType().getValue();
	}
	
	private String sendStatus(String code, String message) {
		Map<String, String> response = new HashMap<String, String>();
		response.put("code", code);
		response.put("message", message == null ? "" : message);
		return sendResponse(response);
	}
	
	private JSONObject formateParam(String requestData) {
		JSONObject requestDataObj = JSON.parseObject(requestData);
		return requestDataObj.getJSONObject(REQUEST_BIZDATA);
	}
	
	private String[] splitRequest(ServletRequest request) {
		String requestUri = ((HttpServletRequest)request).getRequestURI().replaceAll(contentPath, "");
		int index = requestUri.lastIndexOf(".");
		requestUri = requestUri.substring(1, index);
		return requestUri.split("[/]");
	}
	
	private Long saveRequestToDb(String channel, JSONObject param) {
		String ip = request.getRemoteAddr();
		String url = request.getRequestURI();
		
		return DbUtil.getUtil().saveLog(channel, ip, url, JSON.toJSONString(param));
	}
}